"""
电池/步数数据处理器

处理IoT设备的电池电量和步数数据，计算活动强度，记录有效工作时间
"""

import json
from datetime import datetime
from typing import Dict, Any, Optional

import pytz

from .base_handler import BaseHandler
from dao.es_dao.card_dao import update_battery
from model.wristband_models import BatteryData
from utils.date_utils import timestamp_to_date
from utils.mongo_util import db


class BatteryHandler(BaseHandler):
    """电池/步数数据处理器"""
    
    # 活动强度阈值配置
    INTENSITY_THRESHOLDS = {
        'INACTIVE': 0,      # 无活动
        'LIGHT_MOVE': 1,    # 轻微动弹: 1-50步
        'LOW': 2,           # 低强度: 51-250步
        'MEDIUM': 3,        # 中强度: 251-500步
        'HIGH': 4           # 高强度: >500步
    }
    
    def __init__(self):
        super().__init__()
        self.beijing_tz = pytz.timezone('Asia/Shanghai')
    
    async def handle(self, device_id: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """
        处理电池/步数数据
        
        Args:
            device_id: 设备ID
            data: 电池数据字典
            
        Returns:
            处理结果
        """
        try:
            # 将字典数据转换为BatteryData模型
            battery = BatteryData(**data)
            await self._process_battery_data(battery)
            return {"status": "success", "device_id": device_id}
            
        except Exception as e:
            self.log_error(device_id, "电池/步数", e)
            return None
    
    async def _process_battery_data(self, battery: BatteryData) -> None:
        """
        处理电池/步数数据的核心逻辑
        
        业务流程：
        1. 获取设备卡片信息
        2. 计算步数差值（与上次记录对比）
        3. 更新设备电池状态和在线状态
        4. 根据步数计算活动强度
        5. 记录工作时间和活动数据
        
        Args:
            battery: 电池数据模型
        """
        # 步骤1: 获取设备卡片信息
        card = await self.get_device_card(battery.device_id)
        if not card:
            # 记录错误到MongoDB
            await self._log_error_to_mongo(
                battery.device_id, "未获取到card", battery.timestamp
            )
            return
        
        # 步骤2: 计算步数差值
        current_time = datetime.fromtimestamp(battery.timestamp, self.beijing_tz)
        step_difference = await self._calculate_step_difference(
            battery.device_id, battery.pedometer, battery.timestamp, current_time
        )
        
        # 步骤3: 更新设备状态
        await self._update_device_status(battery, card.es_id)
        
        # 步骤4: 记录工作时间和活动强度
        await self._record_work_activity(
            battery.device_id, step_difference, current_time
        )
    
    async def _calculate_step_difference(self, device_id: str, current_steps: int, 
                                       timestamp: int, current_time: datetime) -> int:
        """
        计算步数差值
        
        Args:
            device_id: 设备ID
            current_steps: 当前步数
            timestamp: 当前时间戳
            current_time: 当前时间对象
            
        Returns:
            步数差值
        """
        try:
            # 获取上次步数记录
            last_step_data = await self._get_last_step_record(device_id)
            
            if not last_step_data:
                step_difference = 0
            else:
                last_timestamp = last_step_data['timestamp']
                last_steps = last_step_data['step']
                
                # 检查是否是同一天的数据
                last_date = timestamp_to_date(last_timestamp)
                if current_time.date() == last_date.date():
                    # 同一天，计算步数差值
                    step_difference = max(0, current_steps - last_steps)
                else:
                    # 不同天，重置步数差值
                    step_difference = 0
            
            # 更新最新步数记录
            await self._update_last_step_record(device_id, current_steps, timestamp)
            
            return step_difference
            
        except Exception as e:
            self.logger.error(f"计算步数差值失败: {device_id}, 错误: {e}")
            return 0
    
    async def _get_last_step_record(self, device_id: str) -> Optional[Dict]:
        """
        获取上次步数记录
        
        Args:
            device_id: 设备ID
            
        Returns:
            上次步数记录字典，包含step和timestamp
        """
        try:
            redis_client = self.get_redis_client()
            last_step_bytes = redis_client.hget('step_last', device_id)
            
            if last_step_bytes:
                return json.loads(last_step_bytes.decode('utf-8'))
            return None
            
        except Exception as e:
            self.logger.error(f"获取上次步数记录失败: {device_id}, 错误: {e}")
            return None
    
    async def _update_last_step_record(self, device_id: str, steps: int, timestamp: int) -> None:
        """
        更新最新步数记录到Redis
        
        Args:
            device_id: 设备ID
            steps: 步数
            timestamp: 时间戳
        """
        try:
            redis_client = self.get_redis_client()
            step_data = json.dumps({'step': steps, 'timestamp': timestamp})
            redis_client.hset('step_last', device_id, step_data)
            
        except Exception as e:
            self.logger.error(f"更新步数记录失败: {device_id}, 错误: {e}")
    
    async def _update_device_status(self, battery: BatteryData, card_es_id: str) -> None:
        """
        更新设备电池和在线状态
        
        Args:
            battery: 电池数据
            card_es_id: 卡片ES ID
        """
        try:
            # 更新电池电量
            await update_battery(battery.battery, card_es_id)
            
            # 更新在线状态
            await self.update_device_online_status(battery.timestamp, card_es_id)
            
        except Exception as e:
            self.logger.error(f"更新设备状态失败: {battery.device_id}, 错误: {e}")
    
    async def _record_work_activity(self, device_id: str, step_difference: int, 
                                  current_time: datetime) -> None:
        """
        记录工作活动数据
        
        Args:
            device_id: 设备ID
            step_difference: 步数差值
            current_time: 当前时间
        """
        try:
            # 计算活动强度
            intensity = self._calculate_activity_intensity(step_difference)
            
            # 更新Redis中的活动强度（8分钟TTL）
            await self._update_activity_intensity_redis(
                device_id, intensity, step_difference, current_time
            )
            
            # 如果有活动，记录到MongoDB
            if step_difference > 0:
                await self._save_work_time_to_mongo(
                    device_id, step_difference, current_time, intensity
                )
                
        except Exception as e:
            self.logger.error(f"记录工作活动失败: {device_id}, 错误: {e}")
    
    def _calculate_activity_intensity(self, step_count: int) -> int:
        """
        根据步数计算活动强度
        
        Args:
            step_count: 步数
            
        Returns:
            活动强度等级 (0-4)
        """
        if step_count == 0:
            return self.INTENSITY_THRESHOLDS['INACTIVE']
        elif 1 <= step_count <= 50:
            return self.INTENSITY_THRESHOLDS['LIGHT_MOVE']
        elif 51 <= step_count <= 250:
            return self.INTENSITY_THRESHOLDS['LOW']
        elif 251 <= step_count <= 500:
            return self.INTENSITY_THRESHOLDS['MEDIUM']
        else:  # > 500
            return self.INTENSITY_THRESHOLDS['HIGH']
    
    async def _update_activity_intensity_redis(self, device_id: str, intensity: int,
                                             step_count: int, current_time: datetime) -> None:
        """
        更新活动强度到Redis
        
        Args:
            device_id: 设备ID
            intensity: 活动强度
            step_count: 步数
            current_time: 当前时间
        """
        try:
            redis_client = self.get_redis_client()
            intensity_data = json.dumps({
                'intensity': intensity,
                'step': step_count,
                'date': current_time.timestamp()
            })
            
            # 设置8分钟TTL (480秒)
            redis_client.setex(f'intensity_{device_id}', 480, intensity_data)
            
        except Exception as e:
            self.logger.error(f"更新活动强度Redis失败: {device_id}, 错误: {e}")
    
    async def _save_work_time_to_mongo(self, device_id: str, step_count: int,
                                     current_time: datetime, intensity: int) -> None:
        """
        保存工作时间数据到MongoDB
        
        Args:
            device_id: 设备ID
            step_count: 步数
            current_time: 当前时间
            intensity: 活动强度
        """
        try:
            # 获取围栏状态
            in_fence_status = await self._get_fence_status(device_id)
            
            # 构建工作时间记录
            work_record = {
                'imei': device_id,
                'step': step_count,
                'date': current_time,
                'intensity': intensity,
                'inFence': in_fence_status
            }
            
            # 保存到MongoDB
            db.work_time.insert_one(work_record)
            
        except Exception as e:
            self.logger.error(f"保存工作时间MongoDB失败: {device_id}, 错误: {e}")
    
    async def _get_fence_status(self, device_id: str) -> int:
        """
        获取设备围栏状态
        
        Args:
            device_id: 设备ID
            
        Returns:
            围栏状态：1=在围栏内，0=不在围栏内
        """
        try:
            fence_status = await self.redis_hget_async('in_fence', device_id)
            return int(fence_status) if fence_status else 0
            
        except Exception:
            return 0
    
    async def _log_error_to_mongo(self, device_id: str, error_msg: str, timestamp: int) -> None:
        """
        记录错误信息到MongoDB
        
        Args:
            device_id: 设备ID
            error_msg: 错误消息
            timestamp: 时间戳
        """
        try:
            error_record = {
                'imei': device_id,
                'error': error_msg,
                'timestamp': timestamp_to_date(timestamp)
            }
            db.wristband_logs_error.insert_one(error_record)
            
        except Exception as e:
            self.logger.error(f"记录错误日志失败: {device_id}, 错误: {e}")
    
    # 静态方法：获取设备活动强度（供外部调用）
    @staticmethod
    async def get_device_intensity(device_id: str) -> Dict[str, Any]:
        """
        获取设备活动强度数据
        
        Args:
            device_id: 设备ID
            
        Returns:
            活动强度数据字典
        """
        try:
            from client.redis_client import get_redis_client
            redis_client = get_redis_client()
            
            intensity_data = redis_client.get(f'intensity_{device_id}')
            if intensity_data:
                return json.loads(intensity_data.decode('utf-8'))
            else:
                return {'intensity': 0, 'step': 0, 'date': 0}
                
        except Exception:
            return {'intensity': -1, 'step': 0, 'date': 0}
    
    @staticmethod
    async def get_devices_online_status(device_list: list) -> list:
        """
        批量获取设备在线状态
        
        Args:
            device_list: 设备ID列表
            
        Returns:
            在线状态列表
        """
        try:
            from client.redis_client import get_redis_client
            redis_client = get_redis_client()
            
            keys = [f"intensity_{device_id}" for device_id in device_list]
            results = redis_client.mget(keys)
            
            online_status = []
            for i, device_id in enumerate(device_list):
                if results[i] is None:
                    online_status.append({'imei': device_id, 'online': -1})
                else:
                    intensity_data = json.loads(results[i].decode('utf-8'))
                    online_status.append({
                        'imei': device_id,
                        'online': 1 if intensity_data.get('intensity', 0) > 0 else 0
                    })
            
            return online_status
            
        except Exception:
            return [{'imei': device_id, 'online': -1} for device_id in device_list]